import {
	allMsgCodes,
	courseTypes,
	TISSUE_TYPE,
	USER_TYPE_ADMIN,
	USER_TYPE_ALL,
	USER_TYPE_STUDENT,
	USER_TYPE_THREE,
	emojiRegex2
} from './constant.js'
import CryptoJS from 'crypto-js'

/**
 * 系统环境变量
 */
// 是否测试环境
export const isEnvDev = process.env.NODE_ENV === "development"
// 是否生产环境
export const isEnvProd = process.env.NODE_ENV === "production"
// 是否OA内嵌版本
export const isEnvOaweb = process.env.RUN_ENV === "oaweb"
// 系统环境path
export const envStr = (process.env.RUN_ENV || "dist").toLocaleLowerCase()

// 此系统不支持游客，必需要登录
export const whiteList = ['index', 'course-detail-id']
// tabbar
export let tabBarList = ['/pages/index','/pages/course/list/center', '/pages/user/index','/pages/home/forum']

export const setLogin = (proxy, url, flag = false) => {
	let siteInfo = proxy?.$store.state['siteInfo/info']
	if (siteInfo?.hkDcbSiteWechatConfigDto?.openFlag == 1 && isQyWeixin()) {
		proxy?.$uniPush({
			name: 'wx-redirect-id',
			params: {
				id: siteInfo.domainUrl
			},
			query: {
				path: url
			}
		})
	} else if (siteInfo?.siteWechatOfficialConfigDto?.openFlag == 1 && isWeixin()) {
		proxy?.$uniPush({
			name: 'wx-redirect-id',
			params: {
				id: siteInfo.domainUrl
			},
			query: {
				loginType: 'wx',
				path: url
			}
		})
	} else if (!flag) {
		proxy?.$uniPush({
			name: 'signin-id',
			params: {
				id: siteInfo.courseId
			},
			query: {
				path: url
			}
		})
	}
}
/**
 * 充值对象属性 只支持重置第一层对象
 */
export const resetObject = (o) => {
	for (let i in o) {
		if (Object.prototype.toString.call(i) === '[object Array]') {
			o[i] = []
		}
		if (Object.prototype.toString.call(i) === '[object String]') {
			o[i] = ''
		}
		if (Object.prototype.toString.call(i) === '[object Number]') {
			o[i] = 1
		}
		if (Object.prototype.toString.call(i) === '[object Object]') {
			o[i] = {}
		}
		if (Object.prototype.toString.call(i) === '[object Null]') {
			o[i] = null
		}
		if (Object.prototype.toString.call(i) === '[object Undefined]') {
			o[i] = null
		}
	}
	return o
}

export const isAndroid = () => {
	return Boolean(navigator.userAgent.match(/android/ig))
}
export const isIphone = () => {
	return Boolean(navigator.userAgent.match(/iphone|ipod/ig))
}
export const isIpad = () => {
	return Boolean(navigator.userAgent.match(/ipad/ig))
}
export const isWeixin = () => {
	return Boolean(navigator.userAgent.match(/MicroMessenger/ig))
}
export const isAli = () => {
	return Boolean(navigator.userAgent.match(/AlipayClient/ig))
}
export const isPhone = () => {
	return Boolean(/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent))
}
export const isQyWeixin = () => {
	return Boolean(navigator.userAgent.match(/wxwork/i))
}
export const isDingTalk = () => {
	return Boolean(navigator.userAgent.match(/DingTalk/i))
}
export const getLocalTicket = () => uni.getStorageSync('ssoticket')

export const setLocalTicket = (ticket) => {
	uni.setStorageSync('ssoticket', ticket)
}

export const setSysToken = (ticket) => {
	uni.setStorageSync('access_token', ticket)
}

export const getSysToken = () => {
	return uni.getStorageSync('access_token')
}

export const setWxLoginMode = (mode) => {
	uni.setStorageSync('wx-login-mode', mode)
}

export const getWxLoginMode = () => {
	return uni.getStorageSync('wx-login-mode')
}

export const setCookie = (name, value, day) => {
	if (day) {
		var expires = day * 24 * 60 * 1000
		var date = new Date(+new Date() + expires)
		document.cookie = name + "=" + expires(value) + "=" + date.toUTCString()
	} else {
		document.cookie = name + "=" + escape(value) + ';path=/'
	}
}

export const clearAllCookie = () => {
	var keys = document.cookie.match(/[^ =;]+(?=\=)/g)
	if (keys) {
		for (var i = keys.length; i--;) {
			document.cookie = keys[i] + '=0;path=/;expires=' + new Date(0).toUTCString()
			document.cookie = keys[i] + '=0;path=/;domain=' + document.domain + ';expires=' + new Date(0)
				.toUTCString()
			document.cookie = keys[i] + '=0;path=/;domain=kevis.com;expires=' + new Date(0).toUTCString()
		}
	}
}

export const compareTime = (i, j) => {
	i = i.replace(/-/g, "/")
	j = j.replace(/-/g, "/")
	return new Date(i).getTime() <= new Date(j).getTime()
}

// 解密
export const decryptByDES = (ciphertext, key) => {
	let keyHex = CryptoJS.enc.Utf8.parse(key);
	let decrypted = CryptoJS.DES.decrypt({
		ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
	}, keyHex, {
		mode: CryptoJS.mode.ECB,
		padding: CryptoJS.pad.Pkcs7
	})
	return decrypted.toString(CryptoJS.enc.Utf8)
}

/**
 * [parse json string]
 * @param  {[type]} jsonString [description]
 * @return {[type]}            [description]
 */
export const parse = (jsonString) => {
	if (typeof jsonString === 'object') {
		return jsonString
	}
	try {
		return JSON.parse(jsonString);
	} catch (e) {
		return null;
	}
}

/**
 * [stringify json to json string]
 * @param  {[type]} json [description]
 * @return {[type]}      [description]
 */
export const stringify = (json) => {
	try {
		return JSON.stringify(json);
	} catch (e) {
		return '';
	}
}

/**
 * 获取文件类型
 * @param {*} name 
 */
export const getFileType = (name) => {
	let typeStr = name.replace(/.+\./, "").toLocaleLowerCase()
	let type = ''
	switch (typeStr) {
		case 'png':
		case 'jpg':
		case 'jpeg':
		case 'gif':
			type = 'pic'
			break;
		case 'doc':
		case 'docx':
			type = 'word'
			break;
		case 'txt':
			type = 'txt'
			break;
		case 'xls':
		case 'xlsx':
		case 'csv':
			type = 'excel'
			break;
		case 'pdf':
			type = 'pdf'
			break;
		case 'ppt':
		case 'pptx':
			type = 'ppt'
			break;
		case 'mp3':
		case 'wma':
		case 'avi':
		case 'rm':
		case 'rmvb':
		case 'flv':
		case 'mpg':
		case 'mov':
		case 'mkv':
		case 'FLV':
		case 'mp4':
		case '3gp':
			type = 'video'
			break;
		default:
			type = 'zip'
	}
	return type
}

export const getFileSufixName = (fileName) => {
	if (fileName) {
		let arr = fileName.split('.')
		if (arr.length > 0) {
			return arr[arr.length - 1].toLocaleLowerCase()
		} else {
			return ''
		}
	}
	return ''
}

/**
 * 归纳文件icon
 * @param {*} type 
 * @param {*} fileFormat  后缀
 */
export const transFileType = (type, fileFormat) => {
	if (type === 'V') {
		return 'video'
	} else if (type === 'A') {
		return 'audio'
	} else {
		let res = getFileType(fileFormat.replace('.', ''))
		if (res === 'pic' || res === 'word' || res === 'excel' || res === 'pdf' || res === 'ppt') {
			return res
		} else {
			return 'doc'
		}
	}
}

// 处理子项顺序（添加属性值合并子项单元格）
export const dealItems = (res) => {
	let before = 0
	if (res.length > 0) {
		res.push()
		res.sort(function(a, b) {
			var nameA = a.itemCategoryName.toUpperCase()
			var nameB = b.itemCategoryName.toUpperCase()
			if (nameA < nameB) {
				return -1;
			}
			if (nameA > nameB) {
				return 1;
			}
			return 0;
		})
		// 由于我的比较方法是遍历数组拿数组当前位置和前一个比较，这样做势必会将数组最后一位遗漏，增加一个空对象便利处理完成再删除
		res.push({})
		res.forEach((item, index) => {
			if (index == 0) {

			} else {
				if (item.itemCategoryName == res[index - 1].itemCategoryName) {
					item.tag = 1
				} else {
					if (before == 0) {
						res[0].rowspan = index - before
					} else {
						res[before].rowspan = index - before
					}
					before = index
				}
			}
		})
	}
	res.pop()
	return res
}

// 打开新窗口，CSDN https://blog.csdn.net/yypsober/article/details/79487217
export const openNewWindow = (url) => {
	var tempwindow = window.open('_blank') // 先打开页面
	tempwindow.location = url // 后更改页面地址
}

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
	if (arguments.length === 0) {
		return null
	}
	const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"
	let date
	if (typeof time === "object") {
		date = time
	} else {
		if (typeof time === "string" && /^[0-9]+$/.test(time)) {
			time = parseInt(time)
		}
		if (typeof time === "number" && time.toString().length === 10) {
			time = time * 1000
		}
		date = new Date(time)
	}
	const formatObj = {
		y: date.getFullYear(),
		m: date.getMonth() + 1,
		d: date.getDate(),
		h: date.getHours(),
		i: date.getMinutes(),
		s: date.getSeconds(),
		a: date.getDay(),
	}
	const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
		const value = formatObj[key]
		// Note: getDay() returns 0 on Sunday
		if (key === "a") {
			return ["日", "一", "二", "三", "四", "五", "六"][value]
		}
		return value.toString().padStart(2, "0")
	})
	return time_str
}

export const getConfigName = (type = 'UNIT_SHOW_NAME') => {
	let configMap = uni.getStorageSync('configMap') ? JSON.parse(uni.getStorageSync('configMap')) : {}
	return (type && TISSUE_TYPE[type] && configMap) ? configMap[TISSUE_TYPE[type]] : '-'
}

// 防抖函数
export const debounce = (fn, wait) => {
	var timeout;

	return function() {
		var context = this
		var args = arguments
		clearTimeout(timeout)
		timeout = setTimeout(function() {
			fn.apply(context, args)
		}, wait)
	}
}

/**
 * 解析发布时间
 * （小于1小时显示分钟，大于1小时小于24小时显示‘小时’，大于24小时显示日期）
 * @param {*} time 
 */
export const parseDate = (time) => {
	let result = ''
	if (time) {
		let curr = new Date().getTime()
		time = time.replace(/-/g, "/")
		let old = new Date(time).getTime()
		let hour = 1 * 60 * 60 * 1000
		let minus = curr - old
		if (minus > 0) {
			if (minus < hour) { // 小于一小时
				return Math.ceil(minus / 1000 / 60) + '分钟前'
			} else if (hour <= minus && minus <= 24 * hour) { // 大于1小时小于24小时
				return Math.ceil(minus / hour) + '小时前'
			} else if (minus > 24 * hour) {
				return time
			}
		} else {
			return time
		}
		console.log("-> time", result);

	}
	return result
}

export const decodeURIComponent = (str) => {
	try {
		return window.decodeURIComponent(str)
	} catch (e) {
		return ""
	}
}


/**
 * 生成随机数字
 * @param {*} randomFlag 
 * @param {*} min 
 * @param {*} max 
 */
export const randomWord = (randomFlag, min, max) => {
	var str = "",
		range = min,
		arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
	if (randomFlag) {
		range = Math.round(Math.random() * (max - min)) + min
	}
	for (var i = 0; i < range; i++) {
		var pos = Math.round(Math.random() * (arr.length - 1))
		str += arr[pos]
	}
	return str
}


export const transCourseName = (type) => {
	let str = '—'
	courseTypes.map(item => {
		if (item.id == type) {
			str = item.name
		}
	})
	return str
}

// 计算文件大小
export const calcFileSize = (size) => {
	if (size) {
		return (size / 1024 / 1024).toFixed(2) + ' Mb'
	} else {
		return 0
	}
}

// 上传文件禁用的文件 fileName - 文件名称
export const isUnsupportFiles = (fileName) => {
	if (!fileName) return true // 空名称禁止上传
	let suffix = fileName.split('.')
	if (suffix.length < 2) return true // 不含后缀名称的禁止上传
	suffix = (suffix[suffix.length - 1]).toLocaleLowerCase()
	let unsupportFiles = 'exe,php,asp,jsp,dll,js' // 禁止上传的文件
	return unsupportFiles.indexOf(suffix) > -1
}

// 日期格式化
export const dateFormat = (date, fmt = 'yyyy-MM-dd') => {
	date = date ? new Date(date.replace(/-/g, '/')) : new Date()
	let week = ['日', '一', '二', '三', '四', '五', '六']
	let ret;
	const opt = {
		"y+": date.getFullYear().toString(), // 年
		"M+": (date.getMonth() + 1).toString(), // 月
		"d+": date.getDate().toString(), // 日
		"H+": date.getHours().toString(), // 时
		"m+": date.getMinutes().toString(), // 分
		"s+": date.getSeconds().toString(), // 秒
		"w+": week[date.getDay()], // 周
		// 有其他格式化字符需求可以继续添加，必须转化成字符串
	};
	for (let k in opt) {
		ret = new RegExp("(" + k + ")").exec(fmt);
		if (ret) {
			fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
		};
	};
	return fmt;
}

// 将秒转换成时间字符串 
export const transSecondsToTimeString = (t) => {
	if (t == 0) return '00:00';
	if (t < 60) return "00:" + ((i = t) < 10 ? "0" + i : i);
	if (t < 3600) return "" + ((a = parseInt(t / 60)) < 10 ? "0" + a : a) + ":" + ((i = t % 60) < 10 ? "0" + i : i);
	if (3600 <= t) {
		var a, i, e = parseInt(t / 3600);
		return (e < 10 ? "0" + e : e) + ":" + ((a = parseInt(t % 3600 / 60)) < 10 ? "0" + a : a) + ":" + ((i = t %
			60) < 10 ? "0" + i : i);
	}
	return ''
}

export function formateTimeStamp(timeStamp) {
	var hour;
	var min;
	var seconds;

	hour = parseInt(timeStamp / (60 * 60)) // 计算整数小时数
	var afterHour = timeStamp - hour * 60 * 60 // 取得算出小时数后剩余的秒数
	min = parseInt(afterHour / 60) // 计算整数分
	seconds = parseInt(timeStamp - hour * 60 * 60 - min * 60) // 取得算出分后剩余的秒数

	if (hour < 10) {
		hour = '0' + hour
	}

	if (min < 10) {
		min = '0' + min;
	}

	if (seconds < 10) {
		seconds = '0' + seconds;
	}

	const restTime = {
		hour: hour,
		min: min,
		seconds: seconds
	}
	return restTime
}

// 处理课程错误状态
export const dealFaultLearnStatus = (status) => {
	let str = ''
	switch (status + '') {
		case '1':
			str = '课程未开始'
			break
		case '2':
			str = '课程已结束'
			break
		case '3':
			str = '无权学习'
			break
		case '5':
			str = '请先进入课程选课报名'
			break
		case '6':
			str = '课程报名审批中'
			break
	}
	return str
}

// 生成UUID
export const guid = () => {
	function S4() {
		return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
	}
	return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}

export const copyBasic = (target) => {
	let result = {}
	if (typeof target !== 'object') {
		return
	}
	for (let k in target) {
		if (typeof target[k] !== 'object') {
			result[k] = target[k]
		}
	}
	return result
}

export const deepClone = (target) => {
	let result
	if (typeof target === 'object') {
		if (Array.isArray(target)) {
			result = []
			for (let i in target) {
				result.push(deepClone(target[i]))
			}
		} else if (target === null) {
			result = null
		} else if (target.constructor === RegExp) {
			result = target
		} else {
			result = {}
			for (let i in target) {
				result[i] = deepClone(target[i]);
			}
		}
	} else {
		result = target
	}
	return result
}

export const getTime = (s) => {
	s = parseInt(s || 0)
	let num = s % 60
	let m = s % 3600
	if (s >= 3600) {
		return Math.floor(s / 3600) + '小时' + (m - num ? (m - num) / 60 + '分钟' : '') + (num ? num + '秒' : '')
	} else if (s >= 60) {
		return Math.floor(s / 60) + '分钟' + (num ? num + '秒' : '')
	} else {
		return s + '秒'
	}
}

export const getFormTime = (s) => {
	s = parseInt(s || 0)
	let num = s % 60
	if (s < 60) {
		return '00:' + double(s)
	} else if (s < 3600) {
		return double(Math.floor(s / 60)) + ':' + double(s % 60)
	} else {
		return double(Math.floor(s / 3600)) + ':' + double(Math.floor(s / 60) % 60) + ':' + double(s % 60)
	}
}

const double = (i) => {
	return i > 9 ? i : '0' + i
}

export const getCurrentTime = (time) => {
	let date = new Date()
	if (time) {
		let times = time.split(/-| |:/g)
		let month = parseInt(times[1]) - 1
		date.setFullYear(times[0], month, times[2])
		date.setHours(times[3])
		date.setMinutes(times[4])
		date.setSeconds(times[5])
	}
	return date.getTime()
}

export const getDiffTime = (date, flag) => {
	let stime = getCurrentTime()
	date[1] = parseInt(date[1]) - 1
	let etime = new Date(...date).getTime()
	if (flag && stime > etime) {
		return '已过期'
	}
	// 两个时间戳相差的毫秒数
	let diffTime = (etime - stime) / 1000
	// 计算相差的天数
	let days = Math.floor(diffTime / (24 * 3600))
	// 计算天数后剩余的毫秒数
	let leave1 = diffTime % (24 * 3600)
	// 计算出小时数
	let hours = Math.floor(leave1 / 3600)
	// 计算小时数后剩余的毫秒数
	let leave2 = leave1 % 3600
	// 计算相差分钟数
	let minutes = Math.floor(leave2 / 60)
	let time = days + "天" + hours + "时" + minutes + "分"
	return time
}

export const getSurplusTime = (date, flag) => {
	let stime = getCurrentTime()
	let starttime = new Date(date[0].replace(/-/g, "/")).getTime()
	let endtime = new Date(date[1].replace(/-/g, "/")).getTime()
	if (stime > endtime) {
		return "已过期"
	} else if (stime < endtime && stime > starttime) {
		return "进行中"
	}
	// 两个时间戳相差的毫秒数
	let diffTime = (starttime - stime) / 1000
	// 计算相差的天数
	let days = Math.floor(diffTime / (24 * 3600))
	// 计算天数后剩余的毫秒数
	let leave1 = diffTime % (24 * 3600)
	// 计算出小时数
	let hours = Math.floor(leave1 / 3600)
	// 计算小时数后剩余的毫秒数
	let leave2 = leave1 % 3600
	// 计算相差分钟数
	let minutes = Math.floor(leave2 / 60)
	let time = days + "天" + hours + "时" + minutes + "分"
	return time
}

export const isURL = (str_url) => {
	var strRegex = /(http|https):\/\/([\w.!@#$%^&*()_+-=])*\s*/
	var reg = new RegExp(strRegex)
	return reg.test(str_url)
}

export const dealRegType = (code) => {
	if (code == 1) {
		return '必修'
	} else if (code == 2) {
		return '选修'
	} else if (code == 3) {
		return '选修审批'
	} else {
		// return '—'
		return ''
	}
}

// pic before upload
export const beforePicUpload = (file, vueObj) => {
	const isPIC = (file.fileType === 'image' || file.type === 'image/jpeg' || file.type === 'image/png' || file
		.type === 'image/bmp' || file.type === 'image/gif');
	if (!isPIC) {
		vueObj && vueObj.$toast.fail('图片只支持 JPG/PNG/BMP/GIF 格式!')
		return false
	}
	return true
}

// pic/video before upload
export const beforePicVidUpload = (file, vueObj) => {
	const isPIC = (file.fileType === 'image' || file.fileType === 'video' || file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/bmp' || file
		.type === 'image/gif' || file.type === 'video/mp4')
	if (!isPIC) {
		vueObj && vueObj.$toast.fail('图片和视频只支持 JPG/PNG/BMP/GIF/MP4 格式!')
		return false
	}
	return true
}

// excel before upload
export const beforeExcelUpload = (file, size, vueObj) => {
	const isExcel = (file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file
		.type === 'application/vnd.ms-excel' || file.type === 'text/csv');
	if (!isExcel) {
		vueObj && vueObj.$toast.fail('文件只支持 xlsx/xls/csv 格式!')
		return false
	}
	return true;
}

// pdf before upload
export const beforePdfUpload = (file, size, vueObj) => {
	const isPdf = (file.type === 'application/pdf')
	if (!isPdf) {
		vueObj && vueObj.$toast.fail('文件只支持 pdf 格式!')
		return false
	}
	return true
}

export const leftTimer = (leftDate, currentDate) => {
	if (!leftDate || !currentDate) return ''
	var leftTime = new Date(leftDate).getTime() - new Date(currentDate).getTime() //计算剩余的毫秒数 
	var days = parseInt(leftTime / 1000 / 60 / 60 / 24, 10) //计算剩余的天数 
	var hours = parseInt(leftTime / 1000 / 60 / 60 % 24, 10) //计算剩余的小时 
	var minutes = parseInt(leftTime / 1000 / 60 % 60, 10) //计算剩余的分钟 
	var seconds = parseInt(leftTime / 1000 % 60, 10) //计算剩余的秒数 
	days = days < 10 ? `0${days}` : days
	hours = hours < 10 ? `0${hours}` : hours
	minutes = minutes < 10 ? `0${minutes}` : minutes
	seconds = seconds < 10 ? `0${seconds}` : seconds
	return [days, hours, minutes, seconds]
}

export const dealExamTypeName = (type) => {
	const typeMap = {
		'E': '考试',
		'C': '课程',
		'PW': '实操',
		'EX': '心得',
		'W': '作业',
		'S': '问卷',
		'P': '练习',
		'SI': '考勤',
		'SI_OFFLINE': '线下考勤',
		'L': '直播',
		'PC': '认证',
		'T': '培训',
		'OT': '面授',
		'PUBC': '公开课',
		'TX_MEET': '腾讯会议',
		'MEET': '企业微信会议',
		'OV': '投票',
		'B': '问答社区',
		'K': '知识库',
	};
	return typeMap[type] || "";
}

export const formatJobTitle = (type) => {
	return '【' + dealExamTypeName(type) + '】'
}

// 处理消息
export const getMsgContent = (content) => {
	let jsonContent = parse(content)
	if (jsonContent && jsonContent.content) {
		try {
			// 1.先获得消息主内容，并取的里面的模板名称如{name},{value}之类
			// 2.取对象中这个模板的属性，主要用到颜色和文字
			// 3.替换模板占位符
			let tps = jsonContent.content.match(/\{(.+?)\}/g)
			if (tps && tps.length > 0) {
				for (let i in tps) {
					let tp = tps[i].substr(1, tps[i].length - 2),
						value = jsonContent[tp] ? jsonContent[tp].value : '',
						color = jsonContent[tp] ? jsonContent[tp].color : '',
						font = `<span style="color: var(--color)">${value}</span>`
					jsonContent.content = jsonContent.content.replace(tps[i], font)
				}
			}
			return jsonContent.content
		} catch (e) {
			return ''
		}
	} else {
		return content
	}
}

export const removeRichText = function(html) {
	// 去除富文本样式
	html = html.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
	// 去除图片
	html = html.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/g, '--这是一张图片, 请查看原文--');
	// 去除标签
	html = html.replace(/<[^>]+>/g, '');
	// 去除空白字符
	html = html.trim();
	return html;
}


export const msgToAction = (_this, courseType, courseId, code = '', msgUserId = '', rowData = null, isFormOAPage = '') => {
		if (code === 'MS70001') {
			messageToAction(_this, courseType, courseId, {}, isFormOAPage)
			return
		}
		let leg = allMsgCodes.length,
			path = null
		for (let i = 0; i < leg; i++) {
			let item = allMsgCodes[i]
			if (code === 'MS60001') {
				path = {
					name: item.path,
					params: {
						type: '3',
						id: courseId
					},
					query: {
						isFormOAPage: isFormOAPage,
						...item.query
					}
				}
				_this.$uniPush(path)
				return
			} else if (item.code === code) {
				if (!item.needJump) {
					return
				}
				if (['MS60002', 'MS60003', 'MS60008', 'MS60007'].includes(item
					.code)) { // OA首页消息跳转过来的 报名审核通知 | 流程待审核通知 | 报名结果审核通知 | 流程结果审核通知
					let url = isFormOAPage ? item.OAPath : item.path
					let query = isFormOAPage ? item.OAQuery : item.query
					sessionStorage.setItem('msgTab', query.tab || '')
					path = {
						name: url,
						params: {
							id: courseId
						},
						query: {
							isFormOAPage: isFormOAPage,
							...query
						}
					}
					_this.$uniPush(path)
					return
				} else if (item.path) {
					console.log(`=>(util.js:908) code`, code);
					let params = code === 'MC00001' ? {
						id: msgUserId,
						...item.params
					} : {
						...item.params
					}
					path = {
						name: item.path,
						params: params,
						query: {
							isFormOAPage: isFormOAPage,
							...item.query
						}
					}
					_this.$uniPush(path)
					return
				} else if (item.courseType || courseType) {
					messageToAction(_this, item.courseType || courseType, courseId, item.query, isFormOAPage)
					return
				} else {
					console.log("=>(util.js:1192) item", item);
				}
			} else {
				// console.log("=>(util.js:1196) code, item.code", code, item.code);
			}
		}
	}
export const messageToAction = (_this, courseType, courseId, query, isFormOAPage = '') => {
	let path = null,
		fun = null
	let map = {
		'C': () => {
			path = {name: 'course-detail-id', params: {id: courseId}};
			fun = () => _this.$api.course.courseClick({courseId: courseId})
		},
		'PUBC': () => {
			path = {name: 'course-detail-id', params: {id: courseId}};
			fun = () => _this.$api.course.courseClick({courseId: courseId})
		},
		'DP': () => path = {name: 'home-dailyPractice', params: {id: courseId}},
		'T': () => path = {name: 'training-detail-id', params: {id: courseId}},
		'OT': () => path = {name: 'offlineTrain-detail-id', params: {id: courseId},},
		'PC': () => path = {name: 'certification-detail-id', params: {id: courseId},},
		'E': () => path = {name: 'exam-start-id', params: {id: courseId}, query: {type: courseType}},
		'P': () => path = {name: 'practice-start-id', params: {id: courseId}, query: {type: courseType}},
		'S': () => path = {name: 'questionnaire-start-id', params: {id: courseId},},
		'VO': () => path = {name: 'questionnaire-start-id', params: {id: courseId},},
		'N': () => path = {name: 'signup-detail-id', params: {id: courseId},},
		'TX_MEET': () => path = {name: 'public-living-qywechat', query: {courseRangeType: '1',}},
		'MEET': () => path = {name: 'public-living-qywechat', query: {courseRangeType: '2',}},
		'L': () => path = {name: 'live-list', query: {courseRangeType: '1',}},
		'D': () => path = {name: 'file-type-id', params: {id: courseId},},
		'K': () => path = {name: 'file-type-id', params: {type: '3', id: courseId},},
		'B': () => path = {name: 'forum-detail-id', params: {id: courseId},},
		'CHAPTER': () => {
			path = {name: 'course-detail-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
			fun = () => _this.$api.course.courseClick({courseId: courseId})
		},
		'FORUM': () => {
			path = {name: 'forum-detail-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
			fun = () => _this.$api.forum.clickForum({forumId: courseId})
		},
		'NEWS': () => {
			path = {name: 'news-detail-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
			fun = () => _this.$api.news.clickNum({newsId: courseId})
		},
		'DOC': () => {
			path = {name: 'file-type-id', params: {type: '3', id: courseId}, query: {isFormOAPage: isFormOAPage}}
			fun = () => _this.$api.knowledge.clickDoc({docId: courseId})
		},
		'NOTICE': () => {
			path = {name: 'notice-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
		},
		'TEACHER': () => {
			path = {name: 'teacher-detail-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
		},
		'SIGNUP': () => {
			path = {name: 'signup-detail-id', params: {id: courseId}, query: {isFormOAPage: isFormOAPage}}
		},
	}
	courseType && map[courseType]()
	fun && fun()
	// courseType  && (isFormOAPage ? _this.$uniPush(path) : window.open(_this.$router.resolve(path).href, "_blank"))
	courseType && _this.$uniPush(path)
}

// 判断某个按钮或者菜单是否有权限
export const isPermsKeys = (key, keys) => {
	let index = keys.findIndex((n) => n.perms === key)
	return keys[index]
}

// 关闭页面
export const closeWinPage = () => {
	window.onbeforeunload = null
	try {
		window.opener = null
		window.open('', '_self')
		window.close()
		document.body.remove()
	} catch (e) {
		console.log(e)
	}
}

/**
 * 规则： 首先将参数的key字典排序
 * 2.组成key-value的字符串
 * 3.拼接appkey在字符串最后 SIGN_PRIVATE_KEY = "GuWGP@&s8bAa8lU#iA1g#pFmxsWZqzF$hnZ^Jfi#XQg1HHURZQ6f51@TGSdo%qqn"
 * 4.使用MD5加密
 */
const SIGN_PRIVATE_KEY = "GuWGP@&s8bAa8lU#iA1g#pFmxsWZqzF$hnZ^Jfi#XQg1HHURZQ6f51@TGSdo%qqn"
export const signRequestParamsOld = (data) => {
	let obj = {}
	if (typeof data === 'string') {
		obj = parseQuery('?' + data)
	} else {
		obj = Object.assign({}, data)
	}
	obj.timestamp = data.timestamp
	const objKeys = new Set(['deviceType', 'traceId', 'courseId', 'chapterId', 'studyTimes', 'logId', 'timestamp']);
	const keys = Object.keys(obj).filter(key => objKeys.has(key)).sort();
	const str = keys.map(key => `${key}=${obj[key]}`).join('&') + '&' + SIGN_PRIVATE_KEY;
	return CryptoJS.SHA256(str).toString()
}
export const signRequestParams = (params, uri) => {
	params.timestamp = params.timestamp || new Date().getTime()
	let url = uri.replace('/proxyApi', "")
	url = url.indexOf('?') > -1 ? url.substr(0, url.indexOf('?')) : url
	let str = params.timestamp + url + SIGN_PRIVATE_KEY
	return CryptoJS.SHA256(str).toString()
}

/**
 * 求和
 * @param arr
 * @returns {*}
 */
export function sum(arr) {
	return arr.reduce(function(total, value) {
		return total + value;
	}, 0);
}


export const genUrlToken = () => {
	return '&access_token=' + getSysToken()
}

export const setPhoneNumberUnvisible = (tel) => {
	return tel.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")
}


// PDF预览地址
export const genPDFViewUrl = (url) => {
	return window.location.protocol + '//' + window.location.host + '/hklearn/wap/pdfjs/web/viewer.html?file=' +
		encodeURIComponent(url)
}

// 颜色转换
export const LightenDarkenColor = (col, amt) => {
	var usePound = false;

	if (col[0] == "#") {
		col = col.slice(1);
		usePound = true;
	}

	var num = parseInt(col, 16);

	var r = (num >> 16) + amt;

	if (r > 255) r = 255;
	else if (r < 0) r = 0;

	var b = ((num >> 8) & 0x00FF) + amt;

	if (b > 255) b = 255;
	else if (b < 0) b = 0;

	var g = (num & 0x0000FF) + amt;

	if (g > 255) g = 255;
	else if (g < 0) g = 0;

	return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16);

}
//hex颜色转rgb颜色
function HexToRgb(str) {
	var r = /^\#?[0-9A-F]{6}$/;
	//test方法检查在字符串中是否存在一个模式，如果存在则返回true，否则返回false
	if (!r.test(str)) return alert("输入错误的hex");
	//replace替换查找的到的字符串
	str = str.replace("#", "");
	//match得到查询数组
	var hxs = str.match(/../g);
	//alert('bf:'+hxs)
	for (var i = 0; i < 3; i++) hxs[i] = parseInt(hxs[i], 16);
	//alert(parseInt(80, 16))
	//console.log(hxs);
	return hxs;
}
//GRB颜色转Hex颜色
function RgbToHex(a, b, c) {
	var r = /^\d{1,3}$/;
	if (!r.test(a) || !r.test(b) || !r.test(c)) return alert("输入错误的rgb颜色值");
	var hexs = [a.toString(16), b.toString(16), c.toString(16)];
	for (var i = 0; i < 3; i++)
		if (hexs[i].length == 1) hexs[i] = "0" + hexs[i];
	return "#" + hexs.join("");
}

//得到hex颜色值为color的加深颜色值，level为加深的程度，限0-1之间
function getDarkColor(color, level) {
	var r = /^\#?[0-9A-F]{6}$/;
	if (!r.test(color)) return alert("输入错误的hex颜色值");
	var rgbc = this.HexToRgb(color);
	//floor 向下取整
	for (var i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level));
	return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2]);
}
//得到hex颜色值为color的减淡颜色值，level为加深的程度，限0-1之间
export const getLightColor = (color, level) => {
	var r = /^\#?[0-9A-F]{6}$/;
	if (!r.test(color)) return alert("输入错误的hex颜色值");
	var rgbc = HexToRgb(color);
	for (var i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]);
	return RgbToHex(rgbc[0], rgbc[1], rgbc[2]);
}
/**
 * s 字符串
 */
export const getStrUrl = (s) => {
	// let reg = /(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-)+)/g;
	let reg = /(https?|http|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g,
		str = ''
	str = s.match(reg);
	return (str && str.length ? str[0] : '');
}

export const parseQuery = (url) => {
	let queryObj = {};
	let reg = /[?&]([^=&#]+)=([^&#]*)/g;
	let queryArr = url.match(reg);
	if (queryArr) {
		for (let i in queryArr) {
			let query = queryArr[i].split('=');
			let key = query[0].substr(1),
				value = query[1];
			queryObj[key] ? queryObj[key] = [].concat(queryObj[key], value) : queryObj[key] = value;
		}
	}
	return queryObj;
}


/*
 * @param x {Object} 对象1
 * @param y {Object} 对象2
 * @return  {Boolean} true 为相等，false 为不等
 */
export function deepEqual(x, y) {
	// 指向同一内存时 直接返回true
	if (x === y) {
		return true;
	}
	if ((typeof x === "object" && x !== null) && (typeof y === "object" && y !== null)) {
		if (Object.keys(x).length !== Object.keys(y).length) {
			// 键的数量不相等，直接返回false
			return false;
		}
		for (const prop in x) {
			if (y.hasOwnProperty(prop)) {
				if (!deepEqual(x[prop], y[prop])) return false;
			} else {
				return false;
			}
		}
		return true;
	}
	return false;
}

export const transByte = (bytes) => {
	if (bytes < 1024) {
		return bytes + "b"
	} else {
		let kBytes = bytes / 1024
		if (kBytes < 1024) {
			return (Number.isInteger(kBytes) ? kBytes : kBytes.toFixed(2)) + "Kb"
		} else {
			let mb = kBytes / 1024
			if (mb < 1024) {
				return (Number.isInteger(mb) ? mb : mb.toFixed(2)) + "Mb"
			} else {
				let gb = mb / 1024
				return (Number.isInteger(gb) ? gb : gb.toFixed(2)) + "Gb"
			}
		}
	}
}

/**
 * 获得一个删除参数的url
 * @type {string}
 */
export function delQuery(url) {
	if (url.indexOf('?') !== -1) {
		url = url.replace(/(\?|#)[^'"]*/, '')
	}
	return url
}

// 只能进入学员端
export const onlyInStudent = (val) => {
	return USER_TYPE_STUDENT.includes(val)
}
// 只能进入管理端
export const onlyInAdmin = (val) => {
	return USER_TYPE_ADMIN.includes(val)
}
// 都可以进入
export const stuAndAdminIn = (val) => {
	return USER_TYPE_ALL.includes(val)
}
// 可以进入到管理员端的
export const canInAdmin = (val) => {
	return USER_TYPE_ADMIN.includes(val) || USER_TYPE_ALL.includes(val)
}
// 可以进入到学员端的
export const canInStudent = (val) => {
	return USER_TYPE_STUDENT.includes(val) || USER_TYPE_ALL.includes(val)
}
// 三元模式进入管理员端
export const threeModeInAdmin = (val) => {
	return USER_TYPE_THREE.includes(val)
}

export const setActiveLeftSiteId = (id) => {
	uni.setStorageSync('siteId', id)
}

export const getActiveLeftSiteId = () => {
	return uni.getStorageSync('siteId')
}
export const setStorageSiteInfo = (data) => {
	uni.setStorageSync("siteInfo", JSON.stringify(data))
}

export const getStorageSiteInfo = () => {
	return uni.getStorageSync("siteInfo") && JSON.parse(uni.getStorageSync("siteInfo")) || null
}

export const $toast = {
	fail: (msg, func) => {
		toastFunc('none', msg, func)
	},
	success: (msg, func) => {
		toastFunc('success', msg, func)
	},
	warning: (msg, func) => {
		toastFunc('none', msg, func)
	},
	clear: () => {
		uni.hideLoading()
	},
	loading: (msg) => {
		uni.showLoading({
			title: msg || '加载中'
		})
		return $toast
	}
}

var toastFunc = (type, msg, func, time) => {
	time = typeof time === 'number' ? time : 2000
	uni.showToast({
		title: msg,
		icon: type,
		duration: time,
		success: () => {
			let setTime = setTimeout(() => {
				if (setTime) clearTimeout(setTime)
				func && func()
			}, time)
		}
	})
}

export const $dialog = {
	alert: (params) => {
		return dialogFunc(params)
	},
	confirm: (params, func) => {
		return dialogFunc(params)
	}
}

var dialogFunc = (params = {}) => {
	return new Promise(function(resolve, reject) {
		uni.showModal({
			title: params.title || '提示',
			content: params.message,
			confirmText: '确定',
			confirmColor: params.confirmButtonColor || 'var(--color)',
			success: function(res) {
				if (res.confirm) {
					params.beforeClose && params.beforeClose('', resolve)
					resolve()
				} else if (res.cancel) {
					params.beforeClose && params.beforeClose('', reject)
					reject()
				}
			},
			fail: function(res) {
				reject()
			}
		})
	})
}

export const coverHref = (url) => {
	let reg1 = /\/\d{1,}\?/ig
	let reg2 = /\/\d{1,}$/ig
	let reg3 = /\/detail\/([a-z]|[0-9]|-){1,}$/ig
	let reg4 = /\/detail\/(([a-z]|[0-9]|-){8,})\?/ig
	if (reg1.test(url)) {
		url = url.replace(/(\/)(\d{1,})(\?)/ig, '/detail?id=$2&')
	} else if (reg2.test(url)) {
		url = url.replace(/(\/)(\d{1,})/ig, '/detail?id=$2')
	} else if (reg3.test(url)) {
		url = url.replace(/\/detail\/(([a-z]|[0-9]|-){1,})$/ig, '/detail/detail?id=$1')
	} else if (reg4.test(url)) {
		url = url.replace(/\/detail\/(([a-z]|[0-9]|-){8,})\?/ig, '/detail/detail?id=$1&')
	}
	if (url.indexOf('/pages') < 0) {
		url = '/pages' + url
	}
	return url
}

export const navigateTo = (route) => {
	let url = '',
		arr = []
	if (!route) {
		return false
	}
	url = coverHref(handlePath(route))
	if (tabBarList.indexOf(url.replace(/\?.*/, '')) >= 0) {
		uni.switchTab({
			url: url
		})
	} else {
		uni.navigateTo({
			url: url
		})
	}
}
export const redirectTo = (route) => {
	let url = '',
		arr = []
	if (!route) {
		return false
	}
	url = coverHref(handlePath(route))
	if (tabBarList.indexOf(url.replace(/\?.*/, '')) >= 0) {
		uni.switchTab({
			url: url
		})
	} else {
		uni.redirectTo({
			url: url
		})
	}
}

export const handleVersion = (url, type) => {
	$dialog.confirm({
		title: '发现新版本',
		message: '是否更新到新版本？'
	}).then(() => {
		if (type === 'android') {
			downloadAndInstall(url)
		} else if (type === 'ios') {
			plus.runtime.launchApplication({
			    action: `itms-apps://itunes.apple.com/cn/app/id6504784830`,
			})
		}
	})
}
const downloadAndInstall = (url, type) => {
	uni.downloadFile({
		url: url,
		success: (res) => {
			if (res.statusCode === 200) {
				plus.runtime.install(res.tempFilePath, {
					force: false
				}, () => {
					uni.showToast({
						title: '下载完成',
						icon: 'success'
					});
				}, err => {
					uni.showToast({
						title: '下载失败',
						icon: 'none'
					});
				})
			} else {
				uni.showToast({
					title: res.statusCode,
					icon: 'none'
				})
			}
		}
	})
}

export const setTab = (list) => {
	let arr = []
	for (let i = 0; i < 5; i++) {
		let e = list[i]
		if (e) {
			let icon = handleIcon(e.menuIcon)
			arr.push(handleUrl(e.menuCode, e.goTarget))
			uni.setTabBarItem({
				index: i,
				pagePath: handleUrl(e.menuCode, e.goTarget),
				text: e.menuName,
				iconfont: {
					text: icon,
					selectedText: icon,
					fontSize: "24px",
					color: "#666666",
					selectedColor: "#1EA69D"
				},
			})
		} else {
			uni.setTabBarItem({
				index: i,
				visible: false
			})
		}
	}
	tabBarList = [].concat(arr)
}
const handleUrl = (code, url) => {
	if (code === 'HOME_PATE') {
		url = url.replace('/', '/index')
	} else if (code === 'MY_TASK') {
		url = url.replace('/learn', '/learn/index')
	} else if (code === 'MINE') {
		url = url.replace('/user', '/user/index')
	}
	return '/pages' + url.replace(/\?.*/, '')
}
const iconList = {
	'icon-shouye': '\ue6e1',
	'icon-a-1gerenziliao': '\ue6de',
	'icon-a-1wodekecheng': '\ue67e',
	'icon-xianxiahuodong': '\ue6f5',
	'icon-wodepeixun1': '\ue6f6',
	'icon-baomingzhongxin': '\ue6f4',
	'icon-a-1wodekaoshi': '\ue67c',
	'icon-edit': '\ue6fd',
	'icon-a-1wodecuoti': '\ue67b',
	'icon-a-1wodewenjuan': '\ue685',
	'icon-zhibokecheng': '\ue6e8',
	'icon-zhibo1': '\ue71d',
	'icon-zhishiku': '\ue6e6',
	'icon-wendashequ': '\ue6e4',
	'icon-a-1wodehuati': '\ue686',
	'icon-xinwenzixun': '\ue6e2',
	'icon-gonggao': '\ue6dd',
	'icon-a-1wodexunzhang': '\ue682',
	'icon-a-1wodejifensvg': '\ue679',
	'icon-a-1wodexueshi': '\ue687',
	'icon-a-1xuexitongji': '\ue684',
	'icon-a-1xuexilishi': '\ue681',
	'icon-a-1xuexirili': '\ue677',
	'icon-shoucang1': '\ue6aa',
	'icon-a-1paihangbang': '\ue67a',
	'icon-a-1wodexuefen': '\ue680',
	'icon-a-1wodezhengshu': '\ue683',
	'icon-shenhe': '\ue6e0',
	'icon-laoshi': '\ue701',
	'icon-wodehuifu': '\ue6fc',
	'icon-jiaoxuezhongxin': '\ue6e3'
}
const handleIcon = (code) => {
	return iconList[code] || ''
}
const handlePath = (route) => {
	let url = '',
		arr = []
	if (typeof route === 'object' && route.name) {
		let name = ''
		if (route.name === 'practice-type-id') {
			name = route.name.replace(/-id/, '-detail')
		} else {
			name = route.name.replace(/-type-/, '-').replace(/-id/, '-detail')
		}
		url = '/' + name.replace(/-/ig, '/')
		Object.keys(route.params || {}).forEach(e => {
			arr.push(e + '=' + (route.params[e] === null ? '' : route.params[e]))
		})
		Object.keys(route.query || {}).forEach(e => {
			arr.push(e + '=' + (route.query[e] === null ? '' : route.query[e]))
		})
		url += arr.length ? '?' + arr.join('&') : ''
	}
	if (typeof route === 'object' && route.path) {
		url = route.path
	}
	if (typeof route === 'string') {
		url = route
	}
	return url
}
export function checkType(data) {
	return Object.prototype.toString.call(data)
}

/**
 * 数字转换成中文
 * @param num
 * @returns {string}
 */
export const numToChinese = function (num) {
	let chnNumArr = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
	let chnUnitSection = ['', '万', '亿', '万亿', '亿亿'];
	let chnUnitChar = ['', '十', '百', '千'];

	function sectionToChinese(section) {
		let strIns = '', chnStr = '';
		let unitPos = 0;
		let zero = true;
		while (section > 0) {
			let v = section % 10;
			if (v === 0) {
				if (!zero) {
					zero = true;
					chnStr = chnNumArr[v] + chnStr;
				}
			} else {
				zero = false;
				strIns = chnNumArr[v];
				strIns += chnUnitChar[unitPos];
				chnStr = strIns + chnStr;
			}
			unitPos++;
			section = Math.floor(section / 10);
		}
		return chnStr;
	}

	let unitPos = 0;
	let strIns = '', chnStr = '';
	let needZero = false;
	if (num === 0) {
		return chnNumArr[0];
	}
	while (num > 0) {
		let section = num % 10000;
		if (needZero) {
			chnStr = chnNumArr[0] + chnStr;
		}
		strIns = sectionToChinese(section);
		strIns += (section !== 0) ? chnUnitSection[unitPos] : chnUnitSection[0];
		chnStr = strIns + chnStr;
		needZero = (section < 1000) && (section > 0);
		num = Math.floor(num / 10000);
		unitPos++;
	}
	return chnStr;
}
export const getHtmlContent = (str) => {
	return decodeURIComponent(str)
}
export const getHttpUrl = (val) => {
	let url = val || '';
	if (val) {
	  if (val.indexOf('http') < 0) {
		 url = uni.getStorageSync('domainProtocol') + uni.getStorageSync('domainPath') + val
	  } 
	}
	return url;
  };
// 检测是否包含emoji字符表情
export const haveEmoji = (str) => {
  return emojiRegex2.test(str)
}

// 过滤emoji字符表情
export const removeComplexEmoji = (content='') => {
  console.log(`=>(util.js:1298) str`, content);
  let isArray = Array.isArray(content)
  if (isArray) {
    return content.map(item => {
      return removeComplexEmoji(item)
    })
  }else {
    return content.replace(emojiRegex2, ' ')
  }
} 